package com.zhang.shiro;

import com.zhang.constants.CacheConstant;
import com.zhang.constants.UserConstant;
import com.zhang.dataSource.AbstractDBService;
import com.zhang.modules.api.entity.Api;
import com.zhang.modules.auth.service.IPermissionService;
import com.zhang.modules.user.entity.SysUser;
import com.zhang.modules.user.service.ISysUserService;
import com.zhang.principal.UserInfo;
import com.zhang.principal.impl.SimpleUserInfo;
import com.zhang.service.RedisService;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;


@Component
public class AppDBService extends AbstractDBService {


    @Autowired
    RedisService redisService;

    @Autowired
    ISysUserService sysUserService;

    @Autowired
    IPermissionService permissionService;




    /**
     * 返回用户的基本信息
     */
    @Deprecated
    @Override
    public UserInfo doGetUserInfo(String id) {

        SysUser sysUser = sysUserService.get(id);

        //检查用户状态，禁用用户抛出认证异常
        checkUserStaus(sysUser);

        SimpleUserInfo userInfo = new SimpleUserInfo();

        //设置用户Id
        userInfo.setId(sysUser.getId());

        //认证信息主题设置role权限字符串
        Set<String> roleStrs = new HashSet<>();
        sysUser.getRoles().forEach(item ->{
            roleStrs.add(item.getId());
        });
        userInfo.setRoles(roleStrs);


        //认证信息主题设置prevCode字符串
        HashSet<String> permissionsStrs = new HashSet<>();
        //======>prev loop begin
        userInfo.getRoles().forEach(roleStr ->{
            //获取缓存在redis中的权限字符串，为空去数据库获取，并缓存到redis中
            if (!redisService.hasKey(CacheConstant.CACHE_ROLE_STR_PREFIX+roleStr)){
                Set<String> prevSet = permissionService.findStrByRoleId(roleStr);

                //默认缓存三分钟，三分钟刷新一次权限
                redisService.setCacheObject(CacheConstant.CACHE_ROLE_STR_PREFIX+roleStr,
                                                 prevSet,
                                                 CacheConstant.CACHE_ROLE_STR_Time,
                                                 TimeUnit.SECONDS);
            }
            //从reids中获取权限字符串
            Object cacheObject = redisService.getCacheObject(CacheConstant.CACHE_ROLE_STR_PREFIX+roleStr);
            permissionsStrs.addAll((Set<String>) cacheObject);

        });
        //======>prev loop end
        userInfo.setPermissions(permissionsStrs);


        addmoreInfo(sysUser,userInfo);

        return userInfo;
    }

    /**
     * @param principal 用户信息
     * @param requirePermission {@link Api#getCode()}
     * @return
     */
    @Override
    public boolean isPermitted(UserInfo principal, String requirePermission) {

        boolean resultFlag = false;
        for (String roleStr : principal.getRoles()) {
            //获取缓存在redis中的权限字符串，为空去数据库获取，并缓存到redis中
            if (!redisService.hasKey(CacheConstant.CACHE_ROLE_STR_PREFIX+roleStr)){
                Set<String> prevSet = permissionService.findStrByRoleId(roleStr);

                //默认缓存三分钟，三分钟刷新一次权限
                redisService.setCacheObject(CacheConstant.CACHE_ROLE_STR_PREFIX+roleStr,
                        prevSet,
                        CacheConstant.CACHE_ROLE_STR_Time,
                        TimeUnit.SECONDS);
            }
            //从reids中获取权限字符串
            Set<String> cacheprevs = redisService.getCacheObject(CacheConstant.CACHE_ROLE_STR_PREFIX+roleStr);
            if (cacheprevs.contains(requirePermission)){
                resultFlag = true;
                break;
            }
        }
        return resultFlag;
    }


    /**
     * 检查用户状态
     */
    private static void checkUserStaus(SysUser sysUser) {
        if (sysUser == null) throw new AuthorizationException("用户不存在");

        if (sysUser.getStatus() == UserConstant.USER_STATUS_LOCK) throw new AuthorizationException("用户已被禁用");
    }

    /**
     * 拓展点
     */
    private void addmoreInfo(SysUser sysUser, SimpleUserInfo userInfo) {
        Map<String,Object> externInfo = new HashMap<>();
        //用户昵称
        externInfo.put(UserConstant.USER_NICK_NAME,sysUser.getNickName());
        //用户电话
        externInfo.put(UserConstant.USER_PHONE,sysUser.getPhonenumber());

        userInfo.getExternInfo().putAll(externInfo);

    }


}
